﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WDutils;
using System.Data;
using System.Collections;
using System.Windows.Forms;
using WD.Properties;

namespace WD.Classes
{
    public static class ActivityLogEvents
    {
        /// <summary>
        /// Static string that stores the database table name.
        /// </summary>
        public static string ACTIVITY_LOG_TABLE = "ActivityLog";

        /// <summary>
        /// Public class that gets the collection of ACtivityLog object based on a series of conditions that can be set.
        /// </summary>
        public class GetActivityLogCollection : IBasicRequest
        {
            /// <summary>
            /// Private activityLog object used to store ActivityLogs attributes in order to use them as where conditions.
            /// </summary>
            private ActivityLog objActivityLog;

            private bool boolIncludeDeleted;

            private long longTimeStamp_Start;
            private long longTimeStamp_End;

            /// <summary>
            /// Class used to get a collection of activityLogs based on the set conditions. 
            /// After conditions are set, use Request method to retrive data.
            /// </summary>
            public GetActivityLogCollection()
            {
                this.objActivityLog = new ActivityLog();
                this.boolIncludeDeleted = false;
                this.longTimeStamp_End = 0;
                this.longTimeStamp_Start = 0;
            }

            /// <summary>
            /// Condition setter for the Request based on the ID.
            /// </summary>
            /// <param name="value">ID of the activityLog that should be placed on where condition.</param>
            public void setID(string value)
            {
                this.objActivityLog.setID(value);
            }
            public string getID()
            {
                return this.objActivityLog.getID();
            }

            public void setText(string value)
            {
                this.objActivityLog.setText(value);
            }
            public string getText()
            {
                return this.objActivityLog.getText();
            }

            public void setShowDeleted(bool value)
            {
                this.boolIncludeDeleted = value;
            }

            public void setTimeFilter_Start(long longTimeStamp_Start)
            {
                this.longTimeStamp_Start = longTimeStamp_Start;
            }

            public void setTimeFilter_End(long longTimeStamp_End)
            {
                this.longTimeStamp_End = longTimeStamp_End;
            }

            #region IBasicRequest Members

            public IList Request()
            {
                try
                {
                    SQLiteDatabase db = new SQLiteDatabase();
                    DataTable activityLog = new DataTable();
                    String query = "select *";
                    query += " from " + ACTIVITY_LOG_TABLE;

                    Dictionary <string,string> dictData = this.objActivityLog.getDictData();

                    //Here apply all arrData from the private object for where conditions
                    if (dictData.Count > 0)
                    {
                        query += " where ";
                        int intCounter = dictData.Count;
                        foreach (KeyValuePair<string, string> objDictItemActivityLogAttr in dictData)
                        {
                            query += objDictItemActivityLogAttr.Key + " like '" + objDictItemActivityLogAttr.Value + "'";
                            intCounter--;
                            if(intCounter>0) query += " and ";
                        }
                        if (!this.boolIncludeDeleted) query += " and " + ActivityLog.ACTIVITY_LOG_DELETED_ON + " is NULL";
                        if (this.longTimeStamp_Start != 0) query += " and " + ActivityLog.ACTIVITY_LOG_CREATED_ON + " > " + this.longTimeStamp_Start.ToString();
                        if (this.longTimeStamp_End != 0) query += " and " + ActivityLog.ACTIVITY_LOG_CREATED_ON + " < " + this.longTimeStamp_End.ToString();
                        query += ";";
                    }
                    else
                    {
                        if (!this.boolIncludeDeleted || this.longTimeStamp_Start != 0 || this.longTimeStamp_End != 0) query += " where ";
                        if (!this.boolIncludeDeleted) query += ActivityLog.ACTIVITY_LOG_DELETED_ON + " is NULL and ";
                        if (this.longTimeStamp_Start != 0) query += ActivityLog.ACTIVITY_LOG_CREATED_ON + " > " + this.longTimeStamp_Start.ToString();
                        if (this.longTimeStamp_End != 0) query += " and " + ActivityLog.ACTIVITY_LOG_CREATED_ON + " < " + this.longTimeStamp_End.ToString();
                        query += ";";
                    }

                    //MessageBox.Show(query);

                    activityLog = db.GetDataTable(query);


                    List<ActivityLog> listActivityLogs = new List<ActivityLog>();
                    // Or looped through for some other reason
                    foreach (DataRow r in activityLog.Rows)
                    {
                        listActivityLogs.Add(new ActivityLog(r));
                    }

                    return listActivityLogs;
                }
                catch (Exception fail)
                {
                    String error = "The following error has occurred:\n\n";
                    error += fail.Message.ToString() + "\r\n";
                    error += fail.StackTrace.ToString() + "\r\n";
                    MessageBox.Show(error);
                    return null;
                }
            }

            #endregion

        };

        public class GetActivityLog : GetActivityLogCollection
        {
            public GetActivityLog() { }

            public new ActivityLog Request()
            {
                List<ActivityLog> listActivityLogs = (List<ActivityLog>)base.Request();
                if (listActivityLogs.Count > 0)
                    return listActivityLogs[0];
                else
                    return null;
            }
        };

        public class GetAllActivityLog2GridView
        {
            private DataGridView DGV;
            private bool boolShowDeleted;
            private DateTime dtFilter;
            private String strSearchText;

            public GetAllActivityLog2GridView (DataGridView DGV, bool boolShowDeleted) 
            {
                this.DGV = DGV;
                this.boolShowDeleted = boolShowDeleted;
            }

            public void setGetCondition_TimeFilter(DateTime dtFilter)
            {
                this.dtFilter = dtFilter;
            }

            public void setGetCondition_TextSearch(String strSearchText)
            {
                this.strSearchText = strSearchText.Trim();
            }

            #region IBasicRequest Members

            public void Request()
            {
                List<ActivityLog> listActivityLog = new List<ActivityLog>();

                GetActivityLogCollection eventGetActivityLogCollection = new GetActivityLogCollection();
                eventGetActivityLogCollection.setShowDeleted(this.boolShowDeleted);
                if (this.dtFilter.Year != 1)
                {
                    long longTimeStamp_BeginningOfDay = 0;
                    long longTimeStamp_EndOfDay = 0;

                    longTimeStamp_BeginningOfDay = Utils.Unix.GetUnixTimestampSecondsFromDateTime( Utils.Unix.GetDateTime_BeginningOfDay(dtFilter));
                    longTimeStamp_EndOfDay = Utils.Unix.GetUnixTimestampSecondsFromDateTime( Utils.Unix.GetDateTime_EndOfDay(dtFilter) );

                    eventGetActivityLogCollection.setTimeFilter_Start(longTimeStamp_BeginningOfDay);
                    eventGetActivityLogCollection.setTimeFilter_End(longTimeStamp_EndOfDay);
                }

                if (this.strSearchText != "" && this.strSearchText != null)
                {
                    eventGetActivityLogCollection.setText("%"+this.strSearchText+"%");
                }

                listActivityLog = (List<ActivityLog>)eventGetActivityLogCollection.Request();

                System.Configuration.SettingsPropertyCollection settings = Properties.Settings.Default.Properties;
                int intAttributesCounter = 0;
                foreach (System.Configuration.SettingsProperty property in settings)
                {
                    if (property.Name.Contains("ACTIVITY_LOG_ATTRIB")) intAttributesCounter++;
                }

                DGV.ColumnCount = intAttributesCounter + 4; //+2 from ID + createdon
                DGV.Rows.Clear();

                if (listActivityLog != null)
                {
                    foreach (ActivityLog objActivityLog in listActivityLog)
                    {
                        DGV.Rows.Add(
                            objActivityLog.getID()
                            , objActivityLog.getCreatedOnDateTime().ToLocalTime().ToString()
                            , objActivityLog.getModifiedOnDateTime().ToLocalTime().ToString()
                            , objActivityLog.getDeletedOnDateTime2String()
                            , objActivityLog.getText().ToString()
                            );
                        //TODO if(objActivityLog.getDeletedOnDateTime2String() = "-") add color to the current row to mark deleted.
                    }
                }
                
                DGV.Columns[0].HeaderText = "ID";
                DGV.Columns[0].Width = 40;
                DGV.Columns[0].Name = "ID";
                //DGV.Columns[0].Visible = false;

                DGV.Columns[1].HeaderText = Resources.TXT_ACTIVITY_LOG_CREATED_ON;
                DGV.Columns[1].Name = Resources.TXT_ACTIVITY_LOG_CREATED_ON;
                DGV.Columns[1].Width = 110;
                DGV.Columns[2].HeaderText = Resources.TXT_ACTIVITY_LOG_MODIFIED_ON;
                DGV.Columns[2].Name = Resources.TXT_ACTIVITY_LOG_MODIFIED_ON;
                DGV.Columns[2].Width = 110;
                DGV.Columns[3].HeaderText = Resources.TXT_ACTIVITY_LOG_DELETED_ON;
                DGV.Columns[3].Name = Resources.TXT_ACTIVITY_LOG_DELETED_ON;
                DGV.Columns[3].Width = 0;

                DGV.Columns[4].HeaderText = Resources.TXT_ACTIVITY_LOG_TEXT;
                DGV.Columns[4].Name = Resources.TXT_ACTIVITY_LOG_TEXT;
                DGV.Columns[4].Width = 460;


                //Autoscroll to the bottom of the DGV.
                if (DGV.Rows.Count > 0)
                {
                    DGV.CurrentCell = null;
                    DGV.CurrentCell = DGV.Rows[DGV.Rows.Count - 1].Cells[0];
                }  
            }

            #endregion
        }

        public class InsertActivityLog : IBasicPublish
        {
            private ActivityLog objActivityLog;
            public InsertActivityLog(ActivityLog objActivityLog)
            { 
                this.objActivityLog = objActivityLog;
            }

            #region IBasicPublish Members
            public void Publish()
            {
 	            SQLiteDatabase db = new SQLiteDatabase();
                Dictionary<String, String> data = new Dictionary<String, String>();
                //data.Add(ActivityLog.ACTIVITY_LOG_ID, this.objActivityLog.getID());
                data.Add(ActivityLog.ACTIVITY_LOG_CREATED_ON, this.objActivityLog.getCreatedOn().ToString());
                data.Add(ActivityLog.ACTIVITY_LOG_MODIFIED_ON, this.objActivityLog.getModifiedOn().ToString());
                if(this.objActivityLog.getDeletedOn().ToString() != "0") data.Add(ActivityLog.ACTIVITY_LOG_DELETED_ON, this.objActivityLog.getDeletedOn().ToString());
                data.Add(Properties.Settings.Default.ACTIVITY_LOG_ATTRIB_TEXT, this.objActivityLog.getText());
                try
                {
                    db.Insert(ACTIVITY_LOG_TABLE, data);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
            #endregion
        }

        public class UpdateActivityLog : IBasicPublish
        {
            private ActivityLog objActivityLog;
            public UpdateActivityLog(ActivityLog objActivityLog)
            {
                this.objActivityLog = objActivityLog;
            }

            #region IBasicPublish Members
            public void Publish()
            {
                SQLiteDatabase db = new SQLiteDatabase();
                Dictionary<String, String> data = new Dictionary<String, String>();
                //data.Add(ActivityLog.ACTIVITY_LOG_ID, this.objActivityLog.getID());
                //data.Add(ActivityLog.ACTIVITY_LOG_CREATED_ON, this.objActivityLog.getCreatedOn().ToString());
                data.Add(ActivityLog.ACTIVITY_LOG_MODIFIED_ON, Utils.Unix.GetCurrentUnixTimestampSeconds().ToString());
                if (this.objActivityLog.getDeletedOn() > 0) data.Add(ActivityLog.ACTIVITY_LOG_DELETED_ON, this.objActivityLog.getDeletedOn().ToString());
                if (this.objActivityLog.getDeletedOn() == -1) data.Add(ActivityLog.ACTIVITY_LOG_DELETED_ON, "null");
                data.Add(Properties.Settings.Default.ACTIVITY_LOG_ATTRIB_TEXT, this.objActivityLog.getText());
                try
                {
                    db.Update(ACTIVITY_LOG_TABLE, data, ActivityLog.ACTIVITY_LOG_ID + "=" + this.objActivityLog.getID());
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
            #endregion
        }

        public class DeleteActivityLog : IBasicPublish
        {
            private String strActivityLogID;

            public DeleteActivityLog(String strActivityLogID)
            {
                this.strActivityLogID = strActivityLogID;
            }

            #region IBasicPublish Members
            public void Publish()
            {
                //use update to soft-delete
                ActivityLogEvents.GetActivityLog eventGet = new GetActivityLog();
                eventGet.setShowDeleted(true);
                eventGet.setID(strActivityLogID);
                ActivityLog objDeleteActivityLog = eventGet.Request();

                objDeleteActivityLog.setDeletedOn(Utils.Unix.GetCurrentUnixTimestampSeconds());

                ActivityLogEvents.UpdateActivityLog eventUpdateActivityLog = new UpdateActivityLog(objDeleteActivityLog);
                eventUpdateActivityLog.Publish();
            }
            #endregion
        }

        public class RestoreActivityLog : IBasicPublish
        {
            private String strActivityLogID;

            public RestoreActivityLog(String strActivityLogID)
            {
                this.strActivityLogID = strActivityLogID;
            }

            #region IBasicPublish Members
            public void Publish()
            {
                //use update to soft-delete
                ActivityLogEvents.GetActivityLog eventGet = new GetActivityLog();
                eventGet.setShowDeleted(true);
                eventGet.setID(strActivityLogID);
                ActivityLog objRestoreActivityLog = eventGet.Request();

                objRestoreActivityLog.setDeletedOn(-1);

                ActivityLogEvents.UpdateActivityLog eventUpdateActivityLog = new UpdateActivityLog(objRestoreActivityLog);
                eventUpdateActivityLog.Publish();
            }
            #endregion
        }

        public class PermanentDeleteActivityLog : IBasicPublish
        {
            private String strActivityLogID;

            public PermanentDeleteActivityLog(String strActivityLogID) 
            {
                this.strActivityLogID = strActivityLogID;
            }

            #region IBasicPublish Members
            public void Publish()
            {
                SQLiteDatabase db = new SQLiteDatabase();
                db.Delete(ACTIVITY_LOG_TABLE, "id = " + strActivityLogID);
            }
            #endregion
        }

        /// <summary>
        /// Public class that gets the worked hours from one day.
        /// </summary>
        public class GetActivityLogWorkingHoursPerDay : IBasicRequest
        {
            private bool boolIncludeDeleted;

            private DateTime DTDay;
            
            /// <summary>
            /// Class used to get worked hours from one day
            /// </summary>
            public GetActivityLogWorkingHoursPerDay()
            {
                this.boolIncludeDeleted = false;
                this.DTDay = DateTime.Now;
            }

            public void setShowDeleted(bool value)
            {
                this.boolIncludeDeleted = value;
            }

            public void setDay(DateTime DTDay)
            {
                this.DTDay = DTDay;
            }

            #region IBasicRequest Members

            public IList Request()
            {
                List<double> listWorkHours = new List<double>();

                long longTimeStamp_BeginningOfDay = Utils.Unix.GetUnixTimestampSecondsFromDateTime(
                    Utils.Unix.GetDateTime_BeginningOfDay(this.DTDay));
                long longTimeStamp_EndOfDay = Utils.Unix.GetUnixTimestampSecondsFromDateTime(
                    Utils.Unix.GetDateTime_EndOfDay(this.DTDay));

                ActivityLogEvents.GetActivityLogCollection evGetActivities = new ActivityLogEvents.GetActivityLogCollection();

                evGetActivities.setShowDeleted(this.boolIncludeDeleted);

                evGetActivities.setTimeFilter_Start(longTimeStamp_BeginningOfDay);
                evGetActivities.setTimeFilter_End(longTimeStamp_EndOfDay);

                List<ActivityLog> listActivityLogs4Export = new List<ActivityLog>();

                listActivityLogs4Export = (List<ActivityLog>)(evGetActivities.Request());

                List<ActivityLog> listActivityLogs4Export_Sorted = listActivityLogs4Export.OrderBy(activity => activity.getCreatedOn()).ToList();

                long longCheckInHour = -1;
                long longCheckOutHour = -1;

                long longCumulatedWorkSeconds = 0;

                foreach (ActivityLog objAL in listActivityLogs4Export_Sorted)
                {
                    if (longCheckInHour == -1) longCheckInHour = objAL.getCreatedOn();
                    
                    longCheckOutHour = objAL.getCreatedOn();

                    if (objAL.getText() == ">>out")
                    {//if an >>out token found, calculate interval and reset for next interval;
                        longCheckOutHour = objAL.getCreatedOn();
                        longCumulatedWorkSeconds += longCheckOutHour - longCheckInHour;
                        //reset
                        longCheckInHour = -1;
                    }
                    else
                    {
                        //if it's the LAST activityLog from that day, and no >>out found
                        if (listActivityLogs4Export_Sorted[listActivityLogs4Export_Sorted.Count-1].getID() == objAL.getID())
                        {
                            longCheckOutHour = objAL.getCreatedOn();
                            longCumulatedWorkSeconds += longCheckOutHour - longCheckInHour;
                            //reset
                            longCheckInHour = -1;
                        }
                    }
                }

                listWorkHours.Add((double)(longCumulatedWorkSeconds) / 3600.0);
                listWorkHours.Add((double)(longCumulatedWorkSeconds));

                return listWorkHours;
            }

            #endregion

        };

    }
}
